Skip to content

ci(security): add CodeQL SAST + literal Dockerfile digests (close 7 Scorecard alerts)#431

Merged
SoundMindsAI merged 2 commits into
mainfrom
chore_scorecard_codeql_literal_digests
Jun 3, 2026
Merged

ci(security): add CodeQL SAST + literal Dockerfile digests (close 7 Scorecard alerts)#431
SoundMindsAI merged 2 commits into
mainfrom
chore_scorecard_codeql_literal_digests

Conversation

@SoundMindsAI
Copy link
Copy Markdown
Owner

Follow-up to #430. That PR closed the postcss vulnerability and ~50 pinning alerts; this one closes the remaining genuinely-actionable Scorecard findings — the SAST alert and the 6 containerImage alerts.

CodeQL SAST (#71)

Adds .github/workflows/codeql.yml — GitHub's first-party static analysis on push/PR to main + weekly, scanning python and javascript-typescript (build-mode: none, no compile/service-containers needed). Closes the Scorecard "SAST tool is not run on all commits" finding and, more usefully, runs real static analysis on every PR going forward. Action refs are SHA-pinned to match the repo's pinning posture.

Note: CodeQL may surface its own (real) code-level findings on first run — those are separate alerts to triage, not part of this PR's scope (which is enabling SAST).

Literal Dockerfile digests (#59 / #60 / #80#83)

Reverts the BASE_IMAGE ARG indirection from #430 back to literal image@sha256:… on each FROM. The pin was always real, but Scorecard's static parser only credits a digest it can see inline — an ARG-indirected digest reads as "unpinned", which is exactly what kept all 6 containerImage alerts open. Confirmed from the Scorecard SARIF locations: Dockerfile:24/46/79 + ui/Dockerfile:24/30/39.

Writing tag+digest together on the line also removes the override footgun Gemini flagged on #430, and Dependabot bumps every FROM …@sha256 occurrence in lockstep — so the repeated node digest is not the sync hazard the DRY refactor was trying to avoid.

What's intentionally left (intrinsic / impractical)

npmCommand (npm install -g pnpm@9), pipCommand (docs-site pip install), and the Tier-3 findings (branch protection — relaxed on purpose, solo-dev code-review ratio, project age, fuzzing, OpenSSF badge).

Verification

  • docker buildx build --check on both Dockerfiles ✓ (no warnings, no ${BASE_IMAGE} residue)
  • codeql.yml YAML parses ✓ · reuse lint compliant (1726/1726) ✓
  • CodeQL default-setup confirmed not-configured (no advanced/default conflict)

🤖 Generated with Claude Code

…iterally

Two follow-ups on the post-merge OSSF Scorecard surface (PR #430 closed the
postcss vuln + ~50 pinning alerts; this closes the SAST finding + the 6
remaining containerImage alerts).

CodeQL (#71): add .github/workflows/codeql.yml — GitHub first-party SAST on
push/PR to main + weekly, scanning python + javascript-typescript with
build-mode none. Closes the Scorecard "SAST tool is not run on all commits"
finding and surfaces real code-level bugs on every PR. Action refs pinned to
SHAs to match the repo's pinning posture.

Dockerfile digests (#59/#60/#80-#83): revert the BASE_IMAGE ARG indirection
back to literal `image@sha256:…` on each FROM. The pin was always real, but
Scorecard's static parser only credits a digest it can see inline — an
ARG-indirected digest reads as "unpinned", which is what kept all 6
containerImage alerts open (Dockerfile:24/46/79 + ui/Dockerfile:24/30/39,
confirmed from the Scorecard SARIF locations). Writing tag+digest together also
removes the override footgun Gemini flagged on PR #430; Dependabot bumps every
FROM occurrence in lockstep, so the repeated node digest is not a sync hazard.
Both Dockerfiles pass `docker buildx build --check`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai>
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces ARG-indirected base image digests with inline, literal digest-pinned images in both Dockerfile and ui/Dockerfile to ensure static analysis tools like OSSF Scorecard recognize the pinned dependencies. The review feedback suggests optimizing the multi-stage build in ui/Dockerfile by having the builder stage inherit directly from the deps stage, which avoids redundant setup steps and reduces duplication of the base image digest.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread ui/Dockerfile Outdated
Comment on lines 31 to 34
FROM node:26-bookworm-slim@sha256:79723b41edbedf595f62e943a9f8b0ba9af5b1e61045c5f8f59c2c02c1212a16 AS builder
WORKDIR /app
RUN npm install -g pnpm@9
COPY --from=deps /app/node_modules ./node_modules
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Instead of starting the builder stage from the base image and repeating the setup steps (installing pnpm, setting the working directory, and copying node_modules), you can inherit directly from the deps stage. This avoids redundant network requests/installations and reduces the duplication of the base image digest.

FROM deps AS builder

@github-advanced-security
Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Accept Gemini's finding on PR #431: have the ui builder stage `FROM deps`
instead of re-deriving from the base image. deps already has pnpm, WORKDIR,
and node_modules, so this drops a redundant `npm install -g pnpm@9` + the
node_modules COPY, removes one base-image digest occurrence, and eliminates one
of the two npmCommand Scorecard findings. A stage ref to a digest-pinned stage
is still credited as pinned by Scorecard. node_modules is .dockerignore'd so
`COPY . .` doesn't clobber the installed deps. Verified with a full
`docker buildx build` of the ui image (next build + runner copy succeed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai>
@SoundMindsAI
Copy link
Copy Markdown
Owner Author

Gemini Code Assist adjudication

One finding, accepted and fixed in ec455625.

File Sev Finding Verdict Resolution
ui/Dockerfile:34 medium builder re-derives from the base image and repeats pnpm install + node_modules copy; inherit FROM deps instead. Accept builder now does FROM deps — reuses pnpm/WORKDIR/node_modules, drops the redundant install + copy, removes one base-image digest occurrence, and eliminates one of the two npmCommand Scorecard findings. A stage ref to a digest-pinned stage is still credited as pinned by Scorecard; node_modules is .dockerignore'd so COPY . . doesn't clobber the installed deps. Verified with a full docker buildx build of the ui image (next build + runner copy succeed).

CodeQL (python + javascript-typescript) and both docker buildx jobs green on the final commit.

@SoundMindsAI SoundMindsAI merged commit 5ec2263 into main Jun 3, 2026
16 checks passed
@SoundMindsAI SoundMindsAI deleted the chore_scorecard_codeql_literal_digests branch June 3, 2026 01:51
SoundMindsAI added a commit that referenced this pull request Jun 3, 2026
…n false positives (#432)

* fix(security): use execFileSync in gen-types + document path-injection FP

Address the 3 CodeQL findings from the first scan of main (PR #431 enabled
CodeQL):

- gen-types.mjs (medium, js/shell-command-injection-from-environment): the
  OPENAPI_URL env var was interpolated into an execSync shell string. Switch to
  execFileSync with an args array — no shell, nothing to inject into. It's a
  local dev script (CI never runs it) so the real risk was low, but this is the
  correct pattern regardless. node --check + eslint + prettier clean.

- config_repos.py (high ×2, py/path-injection): false positives. `auth_ref` is
  constrained to `^[a-zA-Z0-9_-]+$` by CreateConfigRepoRequest (no slashes/dots
  → no traversal at the API boundary) AND _auth_ref_exists has a
  resolve()+relative_to() containment guard. CodeQL doesn't model the Pydantic
  pattern or recognize relative_to() as a sanitizer. Added a comment explaining
  the two guards; the alerts are dismissed as reviewed false positives.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai>

* fix(security): resolve npx.cmd on Windows in gen-types (Gemini #432)

Accept Gemini's finding: execFileSync('npx', …) ENOENTs on Windows because the
launcher is npx.cmd and there's no shell to resolve the extension. Pick the
platform-correct executable name. Preserves the no-shell args-array form (the
shell-injection fix); just restores the cross-platform parity the original
execSync had.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai>

---------

Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants